package com.neuronbit.businessflow.flow.source.util;

import com.neuronbit.businessflow.intellij.model.SimpleType;
import com.neuronbit.businessflow.flow.clazz.SourceType;
import com.neuronbit.javaparser.ast.Modifier;
import com.neuronbit.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.neuronbit.javaparser.ast.body.FieldDeclaration;
import com.neuronbit.javaparser.ast.body.VariableDeclarator;
import com.neuronbit.javaparser.ast.expr.Expression;
import com.neuronbit.javaparser.ast.type.ClassOrInterfaceType;
import com.neuronbit.businessflow.intellij.model.Type;
import com.neuronbit.javaparser.resolution.types.ResolvedType;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * The type Field builder.
 */
public final class FieldBuilder {
    private final String name;
    private final Type type;
    private String prefix;
    private Expression initializer;
    private String description;
    private boolean getter = false;

    private List<String> annotations = new ArrayList<>(1);
    private boolean setter = false;
    private Imports imports = new Imports();

    private FieldBuilder(String name, Type type) {
        this.name = name;
        this.type = type;
        imports.add(type);
    }

    /**
     * Builder field builder.
     *
     * @param name the name
     * @param type the type
     * @return the field builder
     */
    public static FieldBuilder builder(String name, Type type) {
        return new FieldBuilder(name, type);
    }

    /**
     * Builder field builder.
     *
     * @param name the name
     * @param type the type
     * @return the field builder
     */
    public static FieldBuilder builder(String name, ResolvedType type) {
        return new FieldBuilder(name, SourceType.of(type));
    }

    /**
     * With getter field builder.
     *
     * @return the field builder
     */
    public FieldBuilder withGetter() {
        getter = true;
        return this;
    }

    /**
     * With setter field builder.
     *
     * @return the field builder
     */
    public FieldBuilder withSetter() {
        setter = true;
        return this;
    }

    /**
     * Prefix field builder.
     *
     * @param prefix the prefix
     * @return the field builder
     */
    public FieldBuilder prefix(String prefix) {
        if (null != prefix) {
            this.prefix = prefix;
        }
        return this;
    }

    /**
     * Initializer field builder.
     *
     * @param initializer the initializer
     * @return the field builder
     */
    public FieldBuilder initializer(Expression initializer) {
        if (null != initializer) {
            this.initializer = initializer;
        }
        return this;
    }

    /**
     * Add annotation field builder.
     *
     * @param annotation the annotation
     * @return the field builder
     */
    public FieldBuilder addAnnotation(String annotation) {
        annotations.add(annotation);
        imports.add(SimpleType.of(annotation));
        return this;
    }

    /**
     * Description field builder.
     *
     * @param description the description
     * @return the field builder
     */
    public FieldBuilder description(String description) {
        this.description = description;
        return this;
    }

    /**
     * Build field declaration.
     *
     * @param clazzOrInterface the clazz or interface
     * @return the field declaration
     */
    public FieldDeclaration buildInto(ClassOrInterfaceDeclaration clazzOrInterface) {
        if (type.isVoid()) {
            return null;
        }
        String fieldName;
        if (StringUtils.isNotBlank(prefix)) {
            fieldName = prefix + StringUtils.capitalize(name);
        } else {
            fieldName = StringUtils.uncapitalize(name);
        }

        FieldDeclaration fieldDeclaration = new FieldDeclaration();
        fieldDeclaration.addModifier(Modifier.Keyword.PRIVATE);  // Set visibility modifier (optional)

        if (StringUtils.isNotBlank(description)) {
            fieldDeclaration.setJavadocComment(description);
        }
        if (null != initializer) {
            fieldDeclaration.addVariable(new VariableDeclarator(new ClassOrInterfaceType(type.getName()), fieldName, initializer));
        } else {
            fieldDeclaration.addVariable(new VariableDeclarator(new ClassOrInterfaceType(type.getName()), fieldName));
        }

        if (!annotations.isEmpty()) {
            for (String annotation : annotations) {
                fieldDeclaration.addAnnotation(annotation);
            }
        }

        clazzOrInterface.addMember(fieldDeclaration);

        if (getter) {
            fieldDeclaration.createGetter();
        }

        if (setter) {
            fieldDeclaration.createSetter();
        }

        imports.install(clazzOrInterface);
        return fieldDeclaration;
    }
}
